﻿<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>Run / RunWait - 语法 &amp; 使用 | AutoHotkey v2</title>
<meta name="description" content="The Run and RunWait functions run an external program. RunWait will wait until the program finishes before continuing." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<style type="text/css">
.style3 {color: #000; background: rgba(255, 255, 0, 0.4);}
</style>
</head>
<body>

<h1>Run / RunWait</h1>

<p>运行外部程序. 与 Run 不同, RunWait 将等到程序完成后才继续.</p>

<pre class="Syntax">
<span class="func">Run</span> Target <span class="optional">, WorkingDir, Options, &amp;OutputVarPID</span>
ExitCode := <span class="func">RunWait</span>(Target <span class="optional">, WorkingDir, Options, &amp;OutputVarPID</span>)
</pre>
<h2 id="Parameters">参数</h2>
<dl>

  <dt>Target</dt>
  <dd>
      <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
      <p>要运行的文档, URL, 可执行文件(.exe, .com, .bat, 等等), 快捷方式(.lnk) 或<a href="#verbs">系统动词</a>(请参阅备注). 如果 <em>Target</em> 是一个本地文件, 并且没有指定路径, 则首先搜索 <a href="../Variables.htm#WorkingDir">A_WorkingDir</a>. 在没有找到匹配的文件时, 如果该文件被集成在系统中("已知的"), 例如包含在 PATH 文件夹中的一个文件夹中, 系统将搜索并启动该文件.</p>
      <p>要传递参数, 请让它们紧跟在程序或文档名的后面. 例如, <code>Run 'MyProgram.exe Param1 Param2'</code>.</p>
      <p>如果程序/文档名称或参数包含空格, 则把它们括在双引号中是最可靠的(虽然它在某些情况下没有括在双引号中也能工作). 例如, <code>Run '"My Program.exe" "param with spaces"'</code>.</p>
  </dd>

  <dt>WorkingDir</dt>
  <dd>
      <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
      <p>用于运行项目的工作目录. 即使它包含空格, 也不要括在双引号中. 如果省略, 则使用脚本自己的工作目录(<a href="../Variables.htm#WorkingDir">A_WorkingDir</a>).</p>
  </dd>

  <dt>Options</dt>
  <dd>
      <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
      <p>如果省略, 函数将正常启动 <em>Target</em>. 要改变此行为, 请指定以下一个或多个单词:</p>
      <p><strong>Max</strong>: 最大化运行</p>
      <p><strong>Min</strong>: 最小化运行</p>
      <p><strong>Hide</strong>: 隐藏运行(不能和上面任意一个选项组合使用)</p>
      <p class="note"><strong>注意</strong>: 一些程序(例如 Calc.exe) 不会遵循请求的启动状态, 因此对于它们 Max/Min/Hide 没有效果.</p>
  </dd>

  <dt>&amp;OutputVarPID</dt>
  <dd>
       <p>类型: <a href="../Concepts.htm#variable-references">VarRef</a></p>
      <p>存储新启动的程序的唯一<a href="../misc/WinTitle.htm#ahk_pid">进程 ID(PID)</a> 的变量引用. 如果无法确定 PID, 该变量将被置为空, 这经常发生在运行系统动词, 文档或快捷方式而不是直接的可执行文件时. RunWait 也支持此参数, 不过它的 <em>OutputVarPID</em> 必须在<a href="../misc/Threads.htm">另一个线程</a>中检查(否则, PID 将是无效的, 因为在 RunWait 后面的线程执行时, 进程已经终止了).</p>
      <p>在 Run 函数检索到 PID 之后, 由进程创建的窗口可能还不存在. 要等待至少一个窗口被创建, 请使用 <code><a href="WinWait.htm">WinWait</a> "ahk_pid " OutputVarPID</code>.</p>
  </dd>

</dl>

<h2 id="Return_Value">返回值</h2>
<p>类型: <a href="../Concepts.htm#numbers">整数</a></p>
<p>与 Run 不同, RunWait 会等待 <em>Target</em> 关闭或退出, 此时返回值被设置为程序的退出代码(32 位的有符号整数). 一些程序即使仍在运行, 但会出现立即返回; 这是因为这些程序启动了另一个进程.</p>

<h2 id="Error_Handling">错误处理</h2>
<p>如果无法启动 <em>Target</em>, 则会抛出异常(即, 显示一个错误窗口) 并退出当前线程, 除非错误被 <a href="Try.htm">Try</a>/<a href="Catch.htm">Catch</a> 语句捕获. 例如:</p>
<pre>try
    Run "NonExistingFile"
catch
    MsgBox "File does not exist."
</pre>
<p>内置变量 <a href="../Variables.htm#LastError">A_LastError</a> 被设置为操作系统的 GetLastError() 函数的结果.</p>
<h2 id="Remarks">备注</h2>
<p>当通过 <a href="../Variables.htm#ComSpec">ComSpec</a>(cmd.exe) 运行程序时 -- 也许是因为你需要重定向程序的输入或输出 -- 如果可执行文件的路径或名称中包含空格, 那么整个字符串应该用一对外置引号来括起. 在下面的例子中, 外部的引号用黄色高亮显示:</p>
<pre>Run A_ComSpec ' /c <span class="style3">"</span>"C:\My Utility.exe" "param 1" "second param" &gt;"C:\My File.txt"<span class="style3">"</span>'</pre>
<p>如果 <em>Target</em> 为准确路径时可轻微提升性能, 例如使用 <code>Run 'C:\Windows\Notepad.exe "C:\My Documents\Test.txt"'</code> 代替 <code>Run "C:\My Documents\Test.txt"</code>.</p>
<p>Run 还可以打开指定的 <a href="../misc/CLSID-List.htm">CLSID 文件夹</a>. 例如:</p>
<pre>Run "::{20d04fe0-3aea-1069-a2d8-08002b30309d}"  <em>; 打开 "我的电脑" 文件夹.</em>
Run "::{645ff040-5081-101b-9f08-00aa002f954e}"  <em>; 打开回收站.</em></pre>
<p id="verbs">系统动词对应于资源管理器中文件的右键菜单中可用的操作. 如果启动文件时没有指定动词, 则使用该文件类型的默认动词(通常为 "打开"). 如果指定了, 则动词后应该跟着目标文件的名称. 目前支持下列动词:</p>
<table class="info">
  <tr>
    <th style="width:8%">Verb(动词)</th>
    <th abbr="Descr">描述</th>
  </tr>
  <tr>
    <td>*<i>verb</i></td>
    <td>任何系统定义或自定义的动词. 例如: <code>Run "*Compile " A_ScriptFullPath</code>. <a href="#RunAs">*RunAs</a> 动词将代替 <i>以管理员身份运行</i> 右键菜单.</td>
  </tr>
  <tr>
    <td>properties</td>
    <td>
      <p>显示指定文件的资源管理器属性窗口. 例如: <code>Run 'properties "C:\My File.txt"'</code></p>
      <p class="note"><strong>注意</strong>: 当脚本终止时属性窗口会自动关闭. 要避免这种情况, 请使用 <a href="WinWait.htm">WinWait</a> 等待窗口出现, 然后使用 <a href="WinWaitClose.htm">WinWaitClose</a> 等待用户关闭它.</p>
    </td>
  </tr>
  <tr>
    <td>find</td>
    <td>在指定的文件夹中打开资源管理器的搜索组件或查找文件窗口的实例. 例如: <code>Run "find D:\"</code></td>
  </tr>
  <tr>
    <td>explore</td>
    <td>打开指定的文件夹的资源管理器实例. 例如: <code>Run "explore " A_ProgramFiles</code>.</td>
  </tr>
  <tr>
    <td>edit</td>
    <td>打开指定的文件进行编辑. 如果指定的文件类型没有关联 "edit" 动作时, 它不起作用. 例如: <code>Run 'edit "C:\My File.txt"'</code></td>
  </tr>
  <tr>
    <td>open</td>
    <td>打开指定的文件(一般不需要, 因为这对于大多数文件类型这是默认的动作). 例如: <code>Run 'open "My File.txt"'</code>.</td>
  </tr>
  <tr>
    <td>print</td>
    <td>使用关联的应用程序打印指定的文件, 如果有. 例如: <code>Run 'print "My File.txt"'</code></td>
  </tr>
</table>
<p>当 RunWait 处于等待状态时, 可以通过<a href="../Hotkeys.htm">热键</a>, <a href="Menu.htm">自定义菜单项</a>或<a href="SetTimer.htm">计时器</a>启动新的<a href="../misc/Threads.htm">线程</a>.</p>

<h2 id="RunAs">以管理员身份运行</h2>
<p>对于可执行文件, <em>*RunAs</em> 动词相当于文件右键菜单的 <em>以管理员身份运行</em>. 例如, 以下代码尝试以管理员权限重启当前脚本:</p>
<pre>full_command_line := DllCall("GetCommandLine", "str")

if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
    try
    {
        if A_IsCompiled
            Run '*RunAs "' A_ScriptFullPath '" /restart'
        else
            Run '*RunAs "' A_AhkPath '" /restart "' A_ScriptFullPath '"'
    }
    ExitApp
}

MsgBox "A_IsAdmin: " A_IsAdmin "`nCommand line: " full_command_line</pre>
<p>如果用户取消了 UAC 对话框, 或者由于其他原因启动失败, 脚本就会直接退出.</p>
<p>如果在调用 ExitApp 之前启动新的脚本实例, 使用 <a href="../Scripts.htm#SlashR">/restart</a> 可以确保不显示<a href="_SingleInstance.htm">单一实例</a>的提示弹窗.</p>
<p>如果禁用了 UAC, <em>*RunAs</em> 将不会提权启动进程. 在命令行中检查 <code>/restart</code> 可以确保在这种情况下脚本不会进入失控循环. 注意 <code>/restart</code> 是一个内置的开关, 所以其不包括在<a href="../Scripts.htm#cmd_args">命令行参数数组</a>中.</p>
<p>可以根据脚本的需要修改上面的例子:</p>
<ul>
  <li>如果脚本的确需要管理员权限, 在 <em>*RunAs</em> 未能提升脚本权限的情况下(例如, 因为 UAC 被禁用), 第二次检查 A_IsAdmin.</li>
  <li>在用户取消了 UAC 提示的情况下, 为了保持脚本的运行, 可以将 ExitApp 移到 try 块中.</li>
  <li>在重新启动失败的情况下, 为了保持脚本的运行(比如脚本文件已被重命名或删除), 移除 ExitApp 并且使用 RunWait 代替 Run. 若是成功, <code>/restart</code> 使新实例终止旧实例. 若是失败, 新实例的退出及 RunWait 返回.</li>
</ul>
<p>AutoHotkey 的安装程序为 <em>.ahk</em> 文件注册 <em>RunAs</em> 动词, 这允许 <code>Run "*RunAs script.ahk"</code> 以管理员权限启动脚本.</p>

<h2 id="Related">相关</h2>
<p><a href="RunAs.htm">RunAs</a>, <a href="Process.htm">进程函数</a>, <a href="Exit.htm">Exit</a>, <a href="../misc/CLSID-List.htm">CLSID 列表</a>, <a href="DllCall.htm">DllCall</a></p>

<h2 id="Examples">示例</h2>
<div class="ex" id="ExBasic">
<p><a class="ex_number" href="#ExBasic"></a> Run 能够从任何目录下启动 Windows 系统程序. 注意, 可执行文件的扩展名如 .exe 可以省略.</p>
<pre>Run "notepad"</pre>
</div>

<div class="ex" id="ExURL">
<p><a class="ex_number" href="#ExURL"></a> Run 能够启动 URLs:</p>
<p>以下是在用户的默认网页浏览器中打开一个互联网地址.</p>
<pre>Run "https://www.google.com"</pre>
<p>以下打开默认的电子邮件应用程序并填写收件人.</p>
<pre>Run "mailto:someone@somedomain.com"</pre>
<p>下面的操作和上面一样, 加上主题和正文.</p>
<pre>Run "mailto:someone@somedomain.com?subject=This is the subject line&amp;body=This is the message body's text."</pre>
</div>

<div class="ex" id="ExErrorLevel">
<p><a class="ex_number" href="#ExErrorLevel"></a> 在最大化应用程序中打开文档, 并在失败时显示一个自定义的错误信息.</p>
<pre>try Run("ReadMe.doc", , "Max")
if A_LastError
    MsgBox "The document could not be launched."</pre>
</div>

<div class="ex" id="ExVerb">
<p><a class="ex_number" href="#ExVerb"></a> 在最小化状态下运行 dir 命令, 并将输出结果存储在文本文件中. 之后, 文本文件及其属性对话框将被打开.</p>
<pre>RunWait A_ComSpec " /c dir C:\ &gt;&gt;C:\DirTest.txt", , "Min"
Run "C:\DirTest.txt"
Run "properties C:\DirTest.txt"
Persistent <em>; 保持脚本不退出, 否则属性对话框将关闭.</em></pre>
</div>

<div class="ex" id="ExCLSID">
<p><a class="ex_number" href="#ExCLSID"></a> Run 能够启动 <a href="../misc/CLSID-List.htm">CLSID</a>:</p>
<p>下面打开回收站.</p>
<pre>Run "::{645ff040-5081-101b-9f08-00aa002f954e}"</pre>
<p>下面打开 "我的电脑" 目录.</p>
<pre>Run "::{20d04fe0-3aea-1069-a2d8-08002b30309d}"</pre>
</div>

<div class="ex" id="ExMultipleCmds">
<p><a class="ex_number" href="#ExMultipleCmds"></a> 要连续运行多个命令, 请每个命令之间使用 "&amp;&amp;".</p>
<pre>Run A_ComSpec "/c dir /b &gt; C:\list.txt &amp;&amp; type C:\list.txt &amp;&amp; pause"</pre>
</div>

<div class="ex" id="ExStdOut">
<p><a class="ex_number" href="#ExStdOut"></a> 以下自定义函数可以用来运行一个命令并检索其输出, 或者一次性运行多个命令并检索其输出.</p>
<pre>MsgBox RunWaitOne("dir " A_ScriptDir)

MsgBox RunWaitMany("
(
echo Put your commands here,
echo each one will be run,
echo and you'll get the output.
)")

RunWaitOne(command) {
    <em>; WshShell object: <a href="http://msdn.microsoft.com/en-us/library/aew9yb99">http://msdn.microsoft.com/en-us/library/aew9yb99</a></em>
    shell := ComObject("WScript.Shell")
    <em>; 通过 cmd.exe 执行单条命令</em>
    exec := shell.Exec(A_ComSpec " /C " command)
    <em>; 读取并返回命令的输出</em>
    return exec.StdOut.ReadAll()
}

RunWaitMany(commands) {
    shell := ComObject("WScript.Shell")
    <em>; 打开 cmd.exe 禁用命令回显</em>
    exec := shell.Exec(A_ComSpec " /Q /K echo off")
    <em>; 发送并执行命令, 使用新行分隔</em>
    exec.StdIn.WriteLine(commands "`nexit")  <em>; 总是在最后退出!</em>
    <em>; 读取并返回所有命令的输出</em>
    return exec.StdOut.ReadAll()
}
</pre>
</div>

<div class="ex" id="ExecScript">
<p><a class="ex_number" href="#ExecScript"></a> 在新的 AutoHotkey 进程中执行给定的代码.</p>
<pre>ExecScript(Script, Wait:=true)
{
    shell := ComObject("WScript.Shell")
    exec := shell.Exec("AutoHotkey.exe /ErrorStdOut *")
    exec.StdIn.Write(script)
    exec.StdIn.Close()
    if Wait
        return exec.StdOut.ReadAll()
}

<em>; 示例:</em>
ib := InputBox("Enter an expression to evaluate as a new script.",,, 'Ord("*")')
if ib.result = "Cancel"
    return
result := ExecScript('FileAppend ' ib.value ', "*"')
MsgBox "Result: " result
</pre>
</div>

</body>
</html>